﻿using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;

namespace Min.ExtendKit.Common.Net;

/// <summary>
/// 提供 IP 相关功能。
/// </summary>
public static class IPHelper
{
    /// <summary>
    /// 检测字符串是否为有效代理 IP 格式，例如 152.40.45.55:8080
    /// </summary>
    /// <param name="proxy">代理字符串</param>
    /// <returns>格式合法返回 true，否则 false</returns>
    public static bool IsValidProxy(string proxy)
    {
        if (string.IsNullOrWhiteSpace(proxy))
            return false;

        var parts = proxy.Split(':');
        if (parts.Length != 2)
            return false;

        if (!IPAddress.TryParse(parts[0], out _))
            return false;

        if (!int.TryParse(parts[1], out int port))
            return false;

        return port >= 1 && port <= 65535;
    }

    /// <summary>
    /// 检查字符串是否符合 IPv4 地址格式。
    /// </summary>
    /// <param name="ip">待检测的 IP 字符串。</param>
    /// <returns>如果是合法 IPv4 地址，返回 <c>true</c>；否则返回 <c>false</c>。</returns>
    public static bool IsValidIPv4(string ip)
    {
        if (!IPAddress.TryParse(ip, out var address)) return false;
        return address.AddressFamily == AddressFamily.InterNetwork;
    }

    /// <summary>
    /// 检查字符串是否符合 IPv6 地址格式。
    /// </summary>
    /// <param name="ip">待检测的 IP 字符串。</param>
    /// <returns>如果是合法 IPv6 地址，返回 <c>true</c>；否则返回 <c>false</c>。</returns>
    public static bool IsValidIPv6(string ip)
    {
        if (!IPAddress.TryParse(ip, out var address)) return false;
        return address.AddressFamily == AddressFamily.InterNetworkV6;
    }

    /// <summary>
    /// 判断字符串是否为合法 IP 地址（IPv4 或 IPv6）
    /// </summary>
    /// <param name="input">待检测字符串</param>
    /// <param name="allowIPv6">是否允许 IPv6，默认 true</param>
    /// <returns>合法返回 true，否则 false</returns>
    public static bool IsIpAddress(string input, bool allowIPv6 = true)
    {
        if (!IPAddress.TryParse(input, out var ip))
            return false;

        if (!allowIPv6 && ip.AddressFamily == AddressFamily.InterNetworkV6)
            return false;

        return true;
    }

    /// <summary>
    /// 判断指定 IP 是否属于私有网段。
    /// IPv4: 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16  
    /// IPv6: fc00::/7
    /// </summary>
    /// <param name="ip">待检测的 <see cref="IPAddress"/> 对象。</param>
    /// <returns>如果是私有网段 IP，返回 <c>true</c>；否则返回 <c>false</c>。</returns>
    public static bool IsPrivateIP(IPAddress ip)
    {
        if (ip == null) return false;

        // 统一判断回环地址
        if (IPAddress.IsLoopback(ip)) return true;

        if (ip.AddressFamily == AddressFamily.InterNetwork)
        {
            var b = ip.GetAddressBytes();
            return (b[0] == 10) || (b[0] == 172 && b[1] >= 16 && b[1] <= 31) || (b[0] == 192 && b[1] == 168) || (b[0] == 169 && b[1] == 254);
        }
        else if (ip.AddressFamily == AddressFamily.InterNetworkV6)
        {
            var b = ip.GetAddressBytes();
            // IPv6 ULA
            if ((b[0] & 0xFE) == 0xFC) return true;
            // IPv6 Link-local
            if ((b[0] == 0xFE) && ((b[1] & 0xC0) == 0x80)) return true;
        }
        return false;
    }

    /// <summary>
    /// 判断指定 IP 是否为回环地址。
    /// IPv4: 127.0.0.0/8, IPv6: ::1
    /// </summary>
    /// <param name="ip">待检测的 <see cref="IPAddress"/> 对象。</param>
    /// <returns>如果是回环地址，返回 <c>true</c>；否则返回 <c>false</c>。</returns>
    public static bool IsLoopback(IPAddress ip)
    {
        return IPAddress.IsLoopback(ip);
    }

    /// <summary>
    /// 判断指定 TCP 端口是否可用（未被占用）。
    /// </summary>
    /// <param name="port">待检测的端口号（1-65535）。</param>
    /// <returns>如果端口可用，返回 <c>true</c>；否则返回 <c>false</c>。</returns>
    public static bool IsPortAvailable(int port)
    {
        if (port < 1 || port > 65535) return false;
        try
        {
            // 使用 TcpListener 检查 TCP 端口
            TcpListener? listener = null;
            try
            {
                listener = new TcpListener(IPAddress.Loopback, port);
                listener.Start();
                return true;
            }
            finally
            {
                // 确保释放资源
                listener?.Stop();
            }
        }
        catch (SocketException)
        {
            // 端口被占用
            return false;
        }
        catch
        {
            return false;
        }
    }

    /// <summary>
    /// 测试代理是否可连通（同步）。
    /// </summary>
    /// <param name="proxy">代理字符串。</param>
    /// <param name="timeoutMs">超时时间，毫秒。</param>
    /// <returns>可连通返回 <c>true</c>，否则 <c>false</c>。</returns>
    public static bool IsProxyReachable(string proxy, int timeoutMs = 2000)
    {
        if (!IsValidProxy(proxy)) return false;
        var parts = proxy.Trim().Split(':');
        var ip = parts[0];
        var port = int.Parse(parts[1]);
        try
        {
            using var client = new TcpClient();
            var task = client.ConnectAsync(ip, port);
            return task.Wait(timeoutMs) && client.Connected;
        }
        catch
        {
            return false;
        }
    }

    /// <summary>
    /// 测试代理是否可连通（异步）。
    /// </summary>
    /// <param name="proxy">代理字符串。</param>
    /// <param name="timeoutMs">超时时间，毫秒。</param>
    /// <returns>可连通返回 <c>true</c>，否则 <c>false</c>。</returns>
    public static async Task<bool> IsProxyReachableAsync(string proxy, int timeoutMs = 2000)
    {
        if (!IsValidProxy(proxy)) return false;
        var parts = proxy.Split(':');
        var ip = parts[0];
        var port = int.Parse(parts[1]);
        try
        {
            using var client = new TcpClient();
            var task = client.ConnectAsync(ip, port);
            var completed = await Task.WhenAny(task, Task.Delay(timeoutMs));
            return completed == task && client.Connected;
        }
        catch
        {
            return false;
        }
    }

    /// <summary>
    /// 获取本机 IP 地址（可选择 IPv4 / IPv6 / 过滤 Loopback）
    /// </summary>
    /// <param name="family">指定协议族，默认 null 返回所有</param>
    /// <param name="excludeLoopback">是否排除本地回环地址，默认 true</param>
    /// <returns>IP 地址集合</returns>
    public static IEnumerable<IPAddress> GetLocalIPAddresses(AddressFamily? family = null, bool excludeLoopback = true)
    {
        try
        {
            var hostName = Dns.GetHostName();
            var ips = Dns.GetHostAddresses(hostName);

            if (family != null)
                ips = ips.Where(ip => ip.AddressFamily == family).ToArray();

            if (excludeLoopback)
                ips = ips.Where(ip => !IPAddress.IsLoopback(ip)).ToArray();

            return ips;
        }
        catch
        {
            // 出错时返回空集合，不抛异常
            return Array.Empty<IPAddress>();
        }
    }

    /// <summary>
    /// 获取本机 IP 地址异步版本。
    /// </summary>
    /// <param name="family">协议族，可选。</param>
    /// <param name="excludeLoopback">是否排除回环地址，默认 true。</param>
    /// <returns>本机 IP 地址集合。</returns>
    public static async Task<IEnumerable<IPAddress>> GetLocalIPAddressesAsync(AddressFamily? family = null, bool excludeLoopback = true)
    {
        return await Task.Run(() => GetLocalIPAddresses(family, excludeLoopback));
    }

    /// <summary>
    /// 获取本机所有网卡的 IPv4 子网掩码。
    /// </summary>
    /// <returns>字典：网卡名称 -> 子网掩码列表。</returns>
    public static Dictionary<string, List<IPAddress>>? GetIPv4SubnetMasks()
    {
        var result = new Dictionary<string, List<IPAddress>>();
        try
        {
            foreach (var ni in NetworkInterface.GetAllNetworkInterfaces())
            {
                if (ni.OperationalStatus != OperationalStatus.Up) continue;
                var masks = ni.GetIPProperties().UnicastAddresses
                    .Where(u => u.Address.AddressFamily == AddressFamily.InterNetwork && u.IPv4Mask != null)
                    .Select(u => u.IPv4Mask!)
                    .Distinct()
                    .ToList();
                if (masks.Count > 0) result[ni.Name] = masks;
            }
        }
        catch
        {
            return null;
        }
        return result;
    }

    /// <summary>
    /// 判断指定 IP 是否属于本机任意网卡
    /// </summary>
    /// <param name="ip">IP 地址字符串</param>
    /// <returns>属于本机返回 true，否则 false</returns>
    public static bool IsLocalIP(string ip)
    {
        if (!IPAddress.TryParse(ip, out var targetIp))
            return false;

        var localIps = GetLocalIPAddresses(family: targetIp.AddressFamily);
        return localIps.Contains(targetIp);
    }

    /// <summary>
    /// 获取 IP 对应的网络地址。
    /// </summary>
    /// <param name="ip">IP 地址。</param>
    /// <param name="mask">子网掩码。</param>
    /// <returns>网络地址。</returns>
    public static IPAddress GetNetworkAddress(IPAddress ip, IPAddress mask)
    {
        var ipBytes = ip.GetAddressBytes();
        var maskBytes = mask.GetAddressBytes();
        var result = new byte[ipBytes.Length];
        for (int i = 0; i < ipBytes.Length; i++) result[i] = (byte)(ipBytes[i] & maskBytes[i]);
        return new IPAddress(result);
    }

    /// <summary>
    /// 获取 IP 对应的广播地址。
    /// </summary>
    /// <param name="ip">IP 地址。</param>
    /// <param name="mask">子网掩码。</param>
    /// <returns>广播地址。</returns>
    public static IPAddress GetBroadcastAddress(IPAddress ip, IPAddress mask)
    {
        var ipBytes = ip.GetAddressBytes();
        var maskBytes = mask.GetAddressBytes();
        var result = new byte[ipBytes.Length];
        for (int i = 0; i < ipBytes.Length; i++) result[i] = (byte)(ipBytes[i] | (~maskBytes[i]));
        return new IPAddress(result);
    }

    /// <summary>
    /// 判断两个 IP 是否在同一子网。
    /// </summary>
    /// <param name="ip1">IP1。</param>
    /// <param name="ip2">IP2。</param>
    /// <param name="mask">子网掩码。</param>
    /// <returns>同子网返回 <c>true</c>，否则 <c>false</c>。</returns>
    public static bool IsSameSubnet(IPAddress ip1, IPAddress ip2, IPAddress mask)
    {
        return GetNetworkAddress(ip1, mask).Equals(GetNetworkAddress(ip2, mask));
    }


}



